/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Project  : WebQQCore
 * Package  : iqq.im
 * File     : WebQQClient.java
 * Author   : solosky < solosky772@qq.com >
 * Created  : 2012-8-1
 * License  : Apache License 2.0
 */
package iqq.mk;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import iqq.im.QQActionListener;
import iqq.im.QQException;
import iqq.im.QQNotifyListener;
import iqq.im.WebQQClient;
import iqq.im.actor.QQActor;
import iqq.im.actor.QQActorDispatcher;
import iqq.im.actor.ThreadActorDispatcher;
import iqq.im.bean.QQAccount;
import iqq.im.bean.QQStatus;
import iqq.im.core.QQContext;
import iqq.im.core.QQModule;
import iqq.im.core.QQService;
import iqq.im.core.QQSession;
import iqq.im.core.QQSession.State;
import iqq.im.core.QQStore;
import iqq.im.event.QQActionFuture;
import iqq.im.event.QQNotifyEvent;
import iqq.im.event.QQNotifyEventArgs;
import iqq.im.event.QQNotifyEventArgs.ImageVerify.VerifyType;
import iqq.im.event.future.ProcActionFuture;
import iqq.im.service.ApacheHttpService;
import iqq.im.service.HttpService;
import iqq.im.service.HttpService.ProxyType;
import iqq.mk.core.MKConstants;
import iqq.mk.module.LoginModule;
import iqq.mk.module.MKModule;
import iqq.mk.module.ProcModule;

/**
 * WebQQ客户的实现
 *
 * @author solosky
 */
public class GameMKClient implements MKClient, QQContext {
    private static final Logger LOG = LoggerFactory.getLogger(WebQQClient.class);
    private Map<QQService.Type, QQService> services;
    private Map<QQModule.Type, QQModule> modules;
    private QQActorDispatcher actorDispatcher;
    private QQAccount account;
    private QQSession session;
    private QQStore store;
    private QQNotifyListener notifyListener;
    public GameMKClient() {
        this("", "", null, new ThreadActorDispatcher());
    }
    public GameMKClient(QQNotifyListener notifyListener, QQActorDispatcher actorDispatcher) {
        this("", "", notifyListener, actorDispatcher);
    }

    /**
     * 构造方法，初始化模块和服务
     * 账号/密码    监听器     线程执行器
     *
     * @param username        a {@link java.lang.String} object.
     * @param password        a {@link java.lang.String} object.
     * @param notifyListener  a {@link iqq.im.QQNotifyListener} object.
     * @param actorDispatcher a {@link iqq.im.actor.QQActorDispatcher} object.
     */
    public GameMKClient(String username, String password,
                       QQNotifyListener notifyListener, QQActorDispatcher actorDispatcher) {
        this.modules = new HashMap<QQModule.Type, QQModule>();
        this.services = new HashMap<QQService.Type, QQService>();

        this.modules.put(QQModule.Type.MK, new MKModule());
        this.modules.put(QQModule.Type.LOGIN, new LoginModule());
        this.modules.put(QQModule.Type.PROC, new ProcModule());
 
        

        this.services.put(QQService.Type.HTTP, new ApacheHttpService());
        this.setHttpUserAgent(MKConstants.HTTP_USER_AGENT);

        this.account = new QQAccount();
        this.account.setUsername(username);
        this.account.setPassword(password);
        this.session = new QQSession();
        this.store = new QQStore();
        this.notifyListener = notifyListener;
        this.actorDispatcher = actorDispatcher;

        this.init();
    }

    /**
     * {@inheritDoc}
     * <p/>
     * 获取某个类型的模块，QQModule.Type
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T extends QQModule> T getModule(QQModule.Type type) {
        return (T) modules.get(type);
    }

    /**
     * {@inheritDoc}
     * <p/>
     * 获取某个类型的服务，QQService.Type
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T extends QQService> T getSerivce(QQService.Type type) {
        return (T) services.get(type);
    }
    
    /**
     * {@inheritDoc}
     * <p/>
     * 获取自己的状态
     */
    @Override
    public boolean isOnline() {
        return getSession().getState() == QQSession.State.ONLINE;
    }

    /**
     * {@inheritDoc}
     * <p/>
     * 获取是否正在登录的状态
     */
    @Override
    public boolean isLogining() {
        return getSession().getState() == QQSession.State.LOGINING;
    }
    
    /**
     * {@inheritDoc}
     * <p/>
     * 设置HTTP的用户信息
     */
    @Override
    public void setHttpUserAgent(String userAgent) {
        HttpService http = getSerivce(QQService.Type.HTTP);
        http.setUserAgent(userAgent);

    }

    /**
     * {@inheritDoc}
     * <p/>
     * 设置代理
     */
    @Override
    public void setHttpProxy(ProxyType proxyType, String proxyHost,
                             int proxyPort, String proxyAuthUser, String proxyAuthPassword) {
        HttpService http = getSerivce(QQService.Type.HTTP);
        http.setHttpProxy(proxyType, proxyHost, proxyPort,
                proxyAuthUser, proxyAuthPassword);
    }

    
    @Override
    public QQAccount getAccount() {
        return account;
    }
    public void setAccount(QQAccount account) {
        this.account = account;
    }
   
    @Override
    public QQStore getStore() {
        return store;
    }
    
    @Override
	public QQSession getSession() {
		// TODO Auto-generated method stub
		return session;
	}
    @Override
    public void fireNotify(QQNotifyEvent event) {
        if (notifyListener != null) {
            try {
                notifyListener.onNotifyEvent(event);
            } catch (Throwable e) {
                LOG.warn("fireNotify Error!!", e);
            }
        }
       /* // 重新登录成功，重新poll
        if (event.getType() == Type.RELOGIN_SUCCESS) {
            beginPollMsg();
        }*/
    }
    @Override
    public void pushActor(QQActor actor) {
        actorDispatcher.pushActor(actor);
    }

    /**
     * 初始化所有模块和服务
     */
    private void init() {
        try {
            for (QQService.Type type : services.keySet()) {
                QQService service = services.get(type);
                service.init(this);
            }

            for (QQModule.Type type : modules.keySet()) {
                QQModule module = modules.get(type);
                module.init(this);
            }

            actorDispatcher.init(this);
            store.init(this);
        } catch (QQException e) {
            LOG.warn("init error:", e);
        }
    }

    /**
     * 销毁所有模块和服务
     */
    public void destroy() {
        try {
            for (QQModule.Type type : modules.keySet()) {
                QQModule module = modules.get(type);
                module.destroy();
            }

            for (QQService.Type type : services.keySet()) {
                QQService service = services.get(type);
                service.destroy();
            }

            actorDispatcher.destroy();
            store.destroy();
        } catch (QQException e) {
            LOG.warn("destroy error:", e);
        }
    }
    /**
     * 获取魔法卡片登录二维码
     *
     * @param qqActionListener
     */
    @Override
    public QQActionFuture getMKRcode(QQActionListener qqActionListener) {
        LoginModule mod = getModule(QQModule.Type.LOGIN);
        return mod.getMKRCode(qqActionListener);
    }

    /**
     * 检测魔法卡片登录二维码是否已经扫描
     *
     * @param qqActionListener
     */
    @Override
    public QQActionFuture checkMKRCode(QQActionListener qqActionListener) {
    	LoginModule mod = getModule(QQModule.Type.LOGIN);
        return mod.checkMKRCode(qqActionListener);
    }

    @Override
	public QQActionFuture getUserMainCardInfo(String descQQ,QQActionListener qqActionListener) {
		MKModule mod = getModule(QQModule.Type.MK);
		return mod.getUserMainCardInfo(descQQ,qqActionListener);
	}
	@Override
	public QQActionFuture getCardCollection(String descQQ, QQActionListener qqActionListener) {
		MKModule mod = getModule(QQModule.Type.MK);
		return mod.getCardCollection(descQQ,qqActionListener);
	}
	@Override
	public QQActionFuture getCardHonor(String descQQ,QQActionListener qqActionListener) {
		MKModule mod = getModule(QQModule.Type.MK);
		return mod.getCardHonor(descQQ,qqActionListener);
	}
	@Override
	@Deprecated
	public QQActionFuture getCardUserThemeList(String themeId,QQActionListener qqActionListener) {
		MKModule mod = getModule(QQModule.Type.MK);
		return mod.getCardUserThemeList(themeId,qqActionListener);
	}
	/**
     * {@inheritDoc}
     * <p/>
     * 登录接口
     */
    @Override
    public QQActionFuture login(QQStatus status, final QQActionListener listener) {
        //检查客户端状态，是否允许登陆
        if (session.getState() == State.ONLINE) {
            throw new IllegalArgumentException(account.getUsername()+" is aready online !!!");
        }

        getAccount().setStatus(status);
        getSession().setState(QQSession.State.LOGINING);
        ProcModule mod = getModule(QQModule.Type.PROC);
        return mod.login(listener);
    }
    /**
     * {@inheritDoc}
     * <p/>
     * 提交验证码
     */
    @Override
    public void submitVerify(String code, QQNotifyEvent verifyEvent) {
        QQNotifyEventArgs.ImageVerify verify =
                (QQNotifyEventArgs.ImageVerify) verifyEvent.getTarget();

        if (verify.type == VerifyType.LOGIN) {
            ProcModule mod = getModule(QQModule.Type.PROC);
            mod.loginWithVerify(code, (ProcActionFuture) verify.future);
        }
    }
}
